/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2025-07-13 21:27:18
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2025-07-14 15:18:54
 * @FilePath: /NetProjectVideo/source_code/data_management.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __MY_DATA__
#define __MY_DATA__

#include "util.hpp"
#include <mutex>
#include <mysql/mysql.h>
#include"util.hpp"
#include <cstdlib>
#include <jsoncpp/json/json.h>

namespace aod
{
// 为了方便，把所有的参数都设置为宏
#define HOST "127.0.0.1"
#define USER "root"
#define PASS "123456"
#define NAME "aod_system"

    // (1)数据库初始化
    static MYSQL *MysqlInit()
    {
        // 1、初始化操作句柄
        MYSQL *mysql = mysql_init(NULL);
        if (mysql == NULL)
        {
            std::cout << "Init failed" << std::endl;
            return NULL;
        }
        // 2、链接MYSQL服务器
        if (mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0, NULL, 0) == NULL)
        {
            std::cout << "connnect failed" << std::endl;
            printf("%s\n", mysql_error(mysql));
            // std::cout << mysql_error(mysql) << std::endl;
            mysql_close(mysql);
            return NULL;
        }
        // 3、设置客户端字符集
        mysql_set_character_set(mysql, "utf8");
        return mysql;
    }
    // (2)数据库销毁
    static void MysqlDestroy(MYSQL *mysql)
    {
        if (mysql != NULL)
        {
            mysql_close(mysql);
        }
        return;
    }
    // (3)数据库执行
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    {
        int ret = mysql_query(mysql, sql.c_str());
        if (ret != 0)
        {
            std::cout << sql << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
        }
        return true;
    }

    class TableVideo
    {
    private:
        MYSQL *_mysql;
        std::mutex _mutex;

    public:
        TableVideo()
        {
            _mysql = MysqlInit();
            if (_mysql == NULL)
            {
                exit(-1);
            }
        }
        ~TableVideo()
        {
            MysqlDestroy(_mysql);
        }


        // 增
        bool Insert(const Json::Value &video)
        {
            // 一个视频的属性有哪些：id,name,info,video,image
               const char* name = video["name"].asCString();
               const char* vdesc = video["info"].asCString();
               const char *video_url = video["video"].asCString();
               const char* image_url = video["image"].asCString();
                char sql[8192] = {0};
#define VIDEO_INSERT "insert tb_video values(null,'%s','%s','%s','%s');"
                sprintf(sql,VIDEO_INSERT, name,vdesc,video_url,image_url);
                return MysqlQuery(_mysql,sql);
        }


        // 删
        bool Delete(int video_id)
        {
#define DELETE_VIDEO "delete from tb_video where id=%d;"
            char sql[1024] = {0};
            sprintf(sql, DELETE_VIDEO, video_id);
            return MysqlQuery(_mysql, sql);
        }


        // 改
        bool Update(int video_id, const Json::Value &video)
        {
            char sql[8192]={0};


            // std::string sql;
            // sql.resize(4096 + video["info"].asString().size()); // 防止info简介过长，空间不够用
#define UPDATE_VIDEO "update tb_video set name='%s',info='%s'where id=%d;"

            sprintf(sql, UPDATE_VIDEO, video["name"].asString(), video["info"].asString(), video_id);
            return MysqlQuery(_mysql, sql);
        }


        // 查
        bool Selectone(int vi_id, Json::Value *vi)
        {
#define SELECTONE "select * from tb_video where id=%d;"
            char sql[1024];
            sprintf(sql, SELECTONE, vi_id);
            _mutex.lock();                            // 加锁：防止一个线程在保存结果的时候，其他线程又来执行语句
            bool ret = MysqlQuery(_mysql, SELECTONE); // 1、执行语句
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }
            // 2、保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "store failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock();

            int num_rows = mysql_num_rows(res);
            if (num_rows != 1)
            {
                std::cout << "have no data" << std::endl;
                mysql_free_result(res);
                return false;
            }

            // 因为我知道只有5列，所以不用两层for循环
            MYSQL_ROW row = mysql_fetch_row(res);
            // Json::Value vi;
            (*vi)["id"] = vi_id;
            (*vi)["name"] = row[1];
            (*vi)["info"] = row[2];
            (*vi)["video"] = row[3];
            (*vi)["image"] = row[4];

            mysql_free_result(res);
            return true;
        }





        bool SelectAll(Json::Value *videos)
        {
#define SELECTALL "select * from tb_video;"
            _mutex.lock();                            // 加锁：防止一个线程在保存结果的时候，其他线程又来执行语句
            bool ret = MysqlQuery(_mysql, SELECTALL); // 1、执行语句
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }
            // 2、保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "store failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock();
            int num_rows = mysql_num_rows(res);
            // 因为我知道只有5列，所以不用两层for循环
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value vi;
                vi["id"] = atoi(row[0]);
                vi["name"] = row[1];
                vi["info"] = row[2];
                vi["video"] = row[3];
                vi["image"] = row[4];

                videos->append(vi);
            }
            mysql_free_result(res);
            return true;
        }




        bool SelectLike(const std::string &key, Json::Value *videos)
        {
#define SELECTLIKE "select * from tb_video where name like '%%%s%%';"

            char sql[1024];
            sprintf(sql, SELECTLIKE, key.c_str());

            _mutex.lock();                            // 加锁：防止一个线程在保存结果的时候，其他线程又来执行语句
            bool ret = MysqlQuery(_mysql, sql); // 1、执行语句
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }
            // 2、保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                std::cout << "store failed!" << std::endl;
                _mutex.unlock();
                return false;
            }
            _mutex.unlock();
            int num_rows = mysql_num_rows(res);
            // 因为我知道只有5列，所以不用两层for循环
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value vi;
                vi["id"] = atoi(row[0]);
                vi["name"] = row[1];
                vi["info"] = row[2];
                vi["video"] = row[3];
                vi["image"] = row[4];

                videos->append(vi);
            }
            mysql_free_result(res);
            return true;           
        }
    };

}

#endif
